home *** CD-ROM | disk | FTP | other *** search
- /* DSM.C
- *
- * Digital Sound Mixer
- *
- * $Id: dsm.c,v 1.11 1997/01/16 18:41:59 pekangas Exp $
- *
- * Copyright 1996,1997 Housemarque Inc.
- *
- * This file is part of the MIDAS Sound System, and may only be
- * used, modified and distributed under the terms of the MIDAS
- * Sound System license, LICENSE.TXT. By continuing to use,
- * modify or distribute this file you indicate that you have
- * read the license and understand and accept it fully.
- */
-
- /* Possibly environment dependent code is marked with *!!* */
-
- #include "lang.h"
- #include "mtypes.h"
- #include "errors.h"
- #include "mmem.h"
- #include "sdevice.h"
- #include "dsm.h"
- #include "mutils.h"
- #include "mglobals.h"
-
- #ifndef NOEMS
- #include "ems.h"
- #endif
-
- #ifdef __DPMI__
- #include "dpmi.h"
- #endif
-
- RCSID(const char *dsm_rcsid = "$Id: dsm.c,v 1.11 1997/01/16 18:41:59 pekangas Exp $";)
-
-
- #ifndef NULL
- #define NULL ((void*) 0L)
- #endif
-
-
- #define MIXBUFLEN 40 /* mixing buffer length 1/40th of a
- second */
-
- unsigned *dsmMixBuffer; /* DSM mixing buffer. dsmPlay() writes
- the mixed data here. Post-
- processing is usually necessary. */
- unsigned dsmMixBufferSize; /* DSM mixing buffer size */
-
- /* The following global variables are used internally by different DSM
- functions and should not be accessed by other modules: */
-
- unsigned dsmMixRate; /* mixing rate in Hz */
- unsigned dsmMode; /* output mode (see enum
- dsmMixMode) */
- #ifdef __16__
- unsigned dsmVolTableSeg; /* volume table segment */
- #endif
- unsigned *dsmVolumeTable; /* pointer to volume table */
-
- dsmChannel *dsmChannels; /* pointer to channel datas */
- dsmSample *dsmSamples; /* sample structures */
- unsigned dsmOutputBits; /* output bit width */
-
-
- /* DSM internal variables: */
-
- static unsigned *dsmVolTableMem; /* pointer to volume table returned
- by memAlloc(). Used for
- deallocating */
- static unsigned dsmChOpen; /* number of open channels */
- static volatile unsigned dsmChPlay; /* 1 if data on channels may be
- played */
- static unsigned dsmMasterVolume; /* master volume */
-
- static int dsmMuted; /* 1 if muted, 0 if not */
- static int dsmPaused; /* 1 if paused, 0 if not */
-
- static unsigned dsmAmplification; /* amplification level */
-
- static void *mixingRoutines[3][5] = /* Pointers to mixing routines */
- {
- {
- /* Make sure we'll crash right away if mixing mode is 0: */
- NULL, NULL, NULL, NULL, NULL
- },
- {
- /* Mixing routines for all sample types to mono output: */
- &dsmMix8bitMonoMono,
- &dsmMix8bitMonoMono,
- &dsmMix16bitMonoMono,
- &dsmMix8bitStereoMono,
- &dsmMix16bitStereoMono
- },
- {
- /* Mixing routines for all sample types to stereo output: */
- &dsmMix8bitMonoStereo,
- &dsmMix8bitMonoStereo,
- &dsmMix16bitMonoStereo,
- &dsmMix8bitStereoStereo,
- &dsmMix16bitStereoStereo
- }
- };
-
-
- /* Calculate log2(sampleSize) based on sample type */
- static int dsmSampleShift(int sampleType)
- {
- switch ( sampleType )
- {
- case smp8bitStereo:
- case smp16bitMono:
- return 1;
-
- case smp16bitStereo:
- return 2;
- }
- return 0;
- }
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmInit(unsigned mixRate, unsigned mode,
- * unsigned outputBits);
- *
- * Description: Initializes Digital Sound Mixer
- *
- * Input: unsigned mixRate mixing rate in Hz
- * unsigned mode mixing mode (see enum dsmMixMode)
- * unsigned outputBits output bit width (if less than
- * 16, output values are divided
- * accordingly - mixing buffer is
- * always a sequence of unsigned ints)
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmInit(unsigned mixRate, unsigned mode, unsigned outputBits)
- {
- int error, i;
- #if defined(__16__) & defined(__PROTMODE__)
- ulong baseAddr
- #endif
-
- dsmMixRate = mixRate;
- dsmMode = mode;
- dsmOutputBits = outputBits;
-
- dsmChOpen = 0; /* no open channels */
- dsmChPlay = 0; /* do not play data in channels */
- dsmChannels = NULL; /* channel structures not allocated */
- dsmMuted = 0; /* not muted */
- dsmPaused = 0; /* not paused */
- dsmMasterVolume = 64; /* master volume maximum */
-
- /* Calculate mixing buffer size: (FIXME) */
- if ( mode == dsmMixStereo )
- dsmMixBufferSize = 2 * sizeof(unsigned) * mixRate / MIXBUFLEN;
- else
- dsmMixBufferSize = sizeof(unsigned) * mixRate / MIXBUFLEN;
-
-
- #if 0
- --------------------
- This code is only for the new fast stereo mixing that is not implemented
- yet
- --------------------
- #ifdef __16__
- if ( mode == dsmMixStereo )
- dsmMixBufferSize = 4 * mixRate / MIXBUFLEN;
- else
- dsmMixBufferSize = 2 * mixRate / MIXBUFLEN;
- #else
- dsmMixBufferSize = sizeof(unsigned) * mixRate / MIXBUFLEN;
- #endif
- #endif /* #if 0 */
-
- /* Round up mixing buffer size to nearest paragraph: */
- dsmMixBufferSize = (dsmMixBufferSize + 15) & 0xFFFFFFF0;
-
- /* Allocate memory for volume table: (mixing buffer follows
- volume table) */
- #ifdef __16__
- if ( (error = memAlloc(VOLLEVELS * 256 * sizeof(unsigned) +
- dsmMixBufferSize+ 16, (void**) &dsmVolTableMem)) != OK )
- PASSERROR(ID_dsmInit);
- #else
- if ( (error = memAlloc(VOLLEVELS * 256 * sizeof(unsigned) +
- dsmMixBufferSize + 1024 + 16,
- (void**) &dsmVolTableMem)) != OK )
- PASSERROR(ID_dsmInit);
- #endif
- /* (in 16-bit modes the volume table is paragraph aligned and in 32-bit
- modes it has to be aligned to a 1024-byte boundary, hence the
- difference) */
-
- #ifdef __16__
- #ifdef __REALMODE__
- /* *!!* */
- /* Real mode - align volume table to a beginning of a segment: */
- dsmVolTableSeg = *((unsigned*) ((uchar*)&dsmVolTableMem + 2)) +
- (((*(unsigned*) &dsmVolTableMem) + 15) >> 4);
- /* (now if that isn't ugly code I don't know what is) */
- #else
- /* 16-bit protected mode under DPMI - allocate descriptor for volume
- table: */
- if ( (error = dpmiAllocDescriptor(&dsmVolTableSeg)) != OK )
- PASSERROR(ID_dsmInit);
-
- /* Get allocated memory area segment base address to baseAddr: */
- if ( (error = dpmiGetSegmentBase((unsigned)
- (((ulong) dsmVolTableMem) >> 16), &baseAddr)) != OK )
- PASSERROR(ID_dsmInit);
-
- /* Calculate volume table memory start address: */
- baseAddr += ((ulong) dsmVolTableMem) & 0xFFFF;
-
- /* Align volume table to paragraph boundary: */
- baseAddr = (baseAddr + 0x0F) & 0xFFFFFFF0L;
-
- /* Set volume table segment base address: */
- if ( (error = dpmiSetSegmentBase(dsmVolTableSeg, baseAddr)) != OK )
- PASSERROR(ID_dsmInit);
-
- /* Set correct segment limit for volume table area (volume table +
- mixing buffer): */
- if ( (error = dpmiSetSegmentLimit(dsmVolTableSeg, 256*2*VOLLEVELS +
- dsmMixBufferSize)) != OK )
- PASSERROR(ID_dsmInit);
- #endif
- /* Point mixing buffer to the memory immediately after the volume
- table: */
- dsmMixBuffer = (unsigned*) ((((ulong) dsmVolTableSeg) << 16) +
- 256 * 2 * VOLLEVELS);
-
- /* Build a normal pointer to the volume table: */
- dsmVolumeTable = (unsigned*) (((ulong) dsmVolTableSeg) << 16);
- #else
- /* 32-bit mode - align volume table to a 1024-byte boundary: */
- dsmVolumeTable = (unsigned*) ((((unsigned) dsmVolTableMem) + 1023) &
- 0xFFFFFC00L);
-
- /* Point mixing buffer to the memory immediately after the volume
- table: */
- dsmMixBuffer = (unsigned*) (((unsigned)dsmVolumeTable) +
- 256 * VOLLEVELS * sizeof(unsigned));
- #endif
-
- /* Allocate memory for sample structures: */
- if ( (error = memAlloc(MAXSAMPLES * sizeof(dsmSample), (void**)
- &dsmSamples)) != OK )
- PASSERROR(ID_dsmInit);
-
- /* Mark all samples unused: */
- for ( i = 0; i < MAXSAMPLES; i++ )
- dsmSamples[i].inUse = 0;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmClose(void)
- *
- * Description: Uninitializes Digital Sound Mixer
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmClose(void)
- {
- int error;
-
- #if defined(__16__) & defined(__PROTMODE__)
- /* Deallocate volume table segment descriptor: */
- if ( (error = dpmiFreeDescriptor(dsmVolTableSeg)) != OK )
- PASSERROR(ID_dsmClose);
- #endif
-
- /* Deallocate volume table and mixing buffer: */
- if ( (error = memFree(dsmVolTableMem)) != OK )
- PASSERROR(ID_dsmClose);
-
- /* Deallocate sample structures: */
- if ( (error = memFree(dsmSamples)) != OK )
- PASSERROR(ID_dsmClose);
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmGetMixRate(unsigned *mixRate)
- *
- * Description: Reads the actual mixing rate
- *
- * Input: unsigned *mixRate pointer to mixing rate variable
- *
- * Returns: MIDAS error code.
- * Mixing rate, in Hz, is stored in *mixRate
- *
- \****************************************************************************/
-
- int CALLING dsmGetMixRate(unsigned *mixRate)
- {
- *mixRate = dsmMixRate;
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmOpenChannels(unsigned channels)
- *
- * Description: Opens channels for output
- *
- * Input: unsigned channels number of channels to open
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmOpenChannels(unsigned channels)
- {
- int error;
-
- dsmChPlay = 0; /* data on channels may not be
- played */
- dsmChOpen = channels;
- dsmMuted = 0; /* not muted */
- dsmPaused = 0; /* not paused */
-
- /* Allocate memory for channel structures: */
- if ( (error = memAlloc(channels * sizeof(dsmChannel), (void**)
- &dsmChannels)) != OK )
- PASSERROR(ID_dsmOpenChannels);
-
- /* Set default amplification level and calculate volume table: */
- if ( (error = dsmSetAmplification(64)) != OK )
- PASSERROR(ID_dsmOpenChannels);
-
- /* Clear all channels: */
- if ( (error = dsmClearChannels()) != OK )
- PASSERROR(ID_dsmOpenChannels);
-
- dsmChPlay = 1; /* data on channels may now be
- played */
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmCalcVolTable(unsigned amplification)
- *
- * Description: Calculates a new volume table
- *
- * Input: unsigned amplification Amplification level. 64 - normal
- * (100%), 32 = 50%, 128 = 200% etc.
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmCalcVolTable(unsigned amplification)
- {
- int volume, value;
- long temp;
- unsigned *tablePtr; /* current volume table position */
-
- /* FIXME - does not support new fast stereo mixing */
-
- tablePtr = dsmVolumeTable;
-
- for ( volume = 0; volume < VOLLEVELS; volume++ )
- {
- for ( value = -128; value < 128; value++ )
- {
- /*!!*/
- temp = ((long) (value * volume)) * ((long) amplification) / 64L;
- temp = (temp * 256L / ((long)(VOLLEVELS-1)) / ((long) dsmChOpen))
- >> (16 - dsmOutputBits);
- *(tablePtr++) = (unsigned) (temp);
- }
- }
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmCloseChannels(void)
- *
- * Description: Closes open output channels
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmCloseChannels(void)
- {
- int error;
-
- /* Check that channels have been opened: */
- if ( dsmChOpen == 0 )
- {
- /* No open channels - return error: */
- ERROR(errNoChannels, ID_dsmCloseChannels);
- return errNoChannels;
- }
-
- dsmChPlay = 0; /* do not play data on channels */
-
- /* Deallocate channel structures: */
- if ( (error = memFree(dsmChannels)) != OK )
- PASSERROR(ID_dsmCloseChannels)
-
- dsmChOpen = 0; /* no open channels */
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmClearChannels(void)
- *
- * Description: Clears open channels (removes all sounds)
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmClearChannels(void)
- {
- unsigned i;
- dsmChannel *chan;
-
- /* Check that channels have been opened: */
- if ( dsmChOpen == 0 )
- {
- /* No open channels - return error: */
- ERROR(errNoChannels, ID_dsmCloseChannels);
- return errNoChannels;
- }
-
- /* Remove sounds from channels: */
- for ( i = 0; i < dsmChOpen; i++ )
- {
- chan = &dsmChannels[i];
- chan->status = dsmChanStopped; /* playing is stopped */
- chan->sampleHandle = 0; /* no sample selected */
- chan->sampleChanged = 0; /* sample not changed */
- chan->sampleType = smpNone; /* no sample */
- chan->samplePos = sdSmpNone; /* no sample */
- chan->rate = 0; /* no playing rate set */
- chan->direction = 1; /* forward direction */
- chan->panning = panMiddle; /* channel at middle */
- chan->muted = 0; /* channel not muted */
- chan->LoopCallback = NULL; /* no loop callback */
- }
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmMute(int mute)
- *
- * Description: Mutes all channels
- *
- * Input: int mute 1 = mute, 0 = un-mute
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmMute(int mute)
- {
- dsmMuted = mute;
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmPause(int pause)
- *
- * Description: Pauses or resumes playing
- *
- * Input: int pause 1 = pause, 0 = resume
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmPause(int pause)
- {
- dsmPaused = pause;
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmSetMasterVolume(unsigned masterVolume)
- *
- * Description: Sets the master volume
- *
- * Input: unsigned masterVolume master volume (0 - 64)
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmSetMasterVolume(unsigned masterVolume)
- {
- dsmMasterVolume = masterVolume;
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmGetMasterVolume(unsigned *masterVolume)
- *
- * Description: Reads the master volume
- *
- * Input: unsigned *masterVolume pointer to master volume
- *
- * Returns: MIDAS error code. Master volume is written to *masterVolume.
- *
- \****************************************************************************/
-
- int CALLING dsmGetMasterVolume(unsigned *masterVolume)
- {
- *masterVolume = dsmMasterVolume;
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmSetAmplification(unsigned amplification)
- *
- * Description: Sets amplification level and calculates new volume table.
- *
- * Input: unsigned amplification amplification level, 64 = normal
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmSetAmplification(unsigned amplification)
- {
- int error;
-
- dsmAmplification = amplification;
-
- if ( (error = dsmCalcVolTable(amplification)) != OK )
- PASSERROR(ID_dsmSetAmplification)
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmGetAmplification(unsigned *amplification)
- *
- * Description: Reads the amplification level
- *
- * Input: unsigned *amplification pointer to amplification level
- *
- * Returns: MIDAS error code. Amplification level is written to
- * *amplification.
- *
- \****************************************************************************/
-
- int CALLING dsmGetAmplification(unsigned *amplification)
- {
- *amplification = dsmAmplification;
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmPlaySound(unsigned channel, ulong rate)
- *
- * Description: Starts playing a sound
- *
- * Input: unsigned channel channel number
- * ulong rate playing rate in Hz
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmPlaySound(unsigned channel, ulong rate)
- {
- int error;
-
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmPlaySound);
- return errInvalidChanNumber;
- }
-
- /* Playing sound: */
- dsmChannels[channel].status = dsmChanPlaying;
-
- /* Set playing rate: */
- if ( (error = dsmSetRate(channel, rate)) != OK )
- PASSERROR(ID_dsmPlaySound)
-
- /* Set playing position to the beginning of the sample: */
- if ( (error = dsmSetPosition(channel, 0)) != OK )
- PASSERROR(ID_dsmPlaySound)
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmReleaseSound(unsigned channel)
- *
- * Description: Releases the current sound from the channel. If sdLoop1Rel or
- * sdLoop2 looping modes are used, playing will be continued from
- * the release part of the current sample (data after the end
- * of the first loop) after the end of the first loop is reached
- * next time, otherwise the sound will be stopped.
- *
- * Input: unsigned channel channel number
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmReleaseSound(unsigned channel)
- {
- dsmChannel *chan;
-
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmReleaseSound);
- return errInvalidChanNumber;
- }
-
- chan = &dsmChannels[channel];
-
- /* If no sound is being played in the channel do nothing: */
- if ( chan->status == dsmChanPlaying )
- {
- if ( (chan->loopMode == sdLoop1Rel) || (chan->loopMode == sdLoop2) )
- {
- /* Release sound - continue from release portion of the sample: */
- chan->status = dsmChanReleased;
- }
- else
- {
- /* One loop only or no looping - let playback continue normally */
- }
- }
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmStopSound(unsigned channel)
- *
- * Description: Stops playing a sound
- *
- * Input: unsigned channel channel number
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmStopSound(unsigned channel)
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmStopSound);
- return errInvalidChanNumber;
- }
-
- /* Stop sound: */
- dsmChannels[channel].status = dsmChanStopped;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmSetRate(unsigned channel, ulong rate)
- *
- * Description: Sets the playing rate
- *
- * Input: unsigned channel channel number
- * ulong rate playing rate in Hz
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmSetRate(unsigned channel, ulong rate)
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmSetRate);
- return errInvalidChanNumber;
- }
-
- /* Set the playing rate: */
- dsmChannels[channel].rate = rate;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmGetRate(unsigned channel, ulong *rate)
- *
- * Description: Reads the playing rate on a channel
- *
- * Input: unsigned channel channel number
- * ulong *rate pointer to playing rate
- *
- * Returns: MIDAS error code. Playing rate is written to *rate, 0 if
- * no sound is being played.
- *
- \****************************************************************************/
-
- int CALLING dsmGetRate(unsigned channel, ulong *rate)
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmGetRate);
- return errInvalidChanNumber;
- }
-
- if ( (dsmChannels[channel].status == dsmChanStopped) ||
- (dsmChannels[channel].status == dsmChanEnd) )
- {
- /* Nothing is being played - write 0 to *rate: */
- *rate = 0;
- }
- else
- {
- /* Write the playing rate: */
- *rate = dsmChannels[channel].rate;
- }
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmSetVolume(unsigned channel, unsigned volume)
- *
- * Description: Sets the playing volume
- *
- * Input: unsigned channel channel number
- * unsigned volume playing volume (0-64)
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmSetVolume(unsigned channel, unsigned volume)
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmSetVolume);
- return errInvalidChanNumber;
- }
-
- /* Set the volume: */
- dsmChannels[channel].volume = volume;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmGetVolume(unsigned channel, unsigned *volume)
- *
- * Description: Reads the playing volume
- *
- * Input: unsigned channel channel number
- * unsigned *volume pointer to volume
- *
- * Returns: MIDAS error code. Playing volume is written to *volume.
- *
- \****************************************************************************/
-
- int CALLING dsmGetVolume(unsigned channel, unsigned *volume)
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmGetVolume);
- return errInvalidChanNumber;
- }
-
- /* Get the volume: */
- *volume = dsmChannels[channel].volume;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmSetSample(unsigned channel, unsigned smpHandle)
- *
- * Description: Sets the sample number on a channel
- *
- * Input: unsigned channel channel number
- * unsigned smpHandle sample handle returned by
- * dsmAddSample()
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmSetSample(unsigned channel, unsigned smpHandle)
- {
- dsmChannel *chan;
- dsmSample *sample;
- int error;
-
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmSetSample);
- return errInvalidChanNumber;
- }
-
- /* Check that the sample handle is valid and the sample is in use: */
- if ( (smpHandle > MAXSAMPLES) || (dsmSamples[smpHandle-1].inUse == 0) )
- {
- ERROR(errInvalidSampleHandle, ID_dsmSetSample);
- return errInvalidSampleHandle;
- }
-
- chan = &dsmChannels[channel];
- sample = &dsmSamples[smpHandle-1];
-
- /* Set new sample number to channel: */
- chan->sampleHandle = smpHandle;
-
- /* Sample has been changed: */
- chan->sampleChanged = 1;
-
- /* If the new sample has one Amiga-compatible loop and playing has ended
- (not released or stopped), set the new sample and start playing from
- loop start: */
- if ( (sample->loopMode == sdLoopAmiga) && (chan->status == dsmChanEnd) )
- {
- /* Set sample and start playing: */
- chan->status = dsmChanPlaying;
- if ( (error = dsmSetPosition(channel, sample->loop1Start)) != OK )
- PASSERROR(ID_dsmSetSample)
- }
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmGetSample(unsigned channel, unsigned *smpHandle)
- *
- * Description: Reads current sample handle
- *
- * Input: unsigned channel channel number
- * unsigned *smpHandle pointer to sample handle
- *
- * Returns: MIDAS error code. Sample handle is written to *smpHandle;
- *
- \****************************************************************************/
-
- int CALLING dsmGetSample(unsigned channel, unsigned *smpHandle)
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmGetSample);
- return errInvalidChanNumber;
- }
-
- /* Write sample handle to *smpHandle: */
- *smpHandle = dsmChannels[channel].sampleHandle;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmChangeSample(unsigned channel)
- *
- * Description: Changes the sample used in a channel to the one specified
- * by the channel's sample handle. Used only internally by
- * other DSM functions, does no error checking.
- *
- * Input: unsigned channel channel number
- *
- * Returns: MIDAS error code (does not fail)
- *
- \****************************************************************************/
-
- int CALLING dsmChangeSample(unsigned channel)
- {
- dsmChannel *chan = &dsmChannels[channel];
- dsmSample *sample = &dsmSamples[chan->sampleHandle-1];
-
- /* Start using the sample specified by chan->sampleHandle: */
-
- chan->sample = sample->sample;
- chan->sampleType = sample->sampleType;
- chan->samplePos = sample->samplePos;
- chan->sampleLength = sample->sampleLength;
- chan->loopMode = sample->loopMode;
- chan->loop1Start = sample->loop1Start;
- chan->loop1End = sample->loop1End;
- chan->loop1Type = sample->loop1Type;
- chan->loop2Start = sample->loop2Start;
- chan->loop2End = sample->loop2End;
- chan->loop2Type = sample->loop2Type;
- chan->sampleChanged = 0;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmSetPosition(unsigned channel, unsigned position)
- *
- * Description: Sets the playing position from the beginning of the sample
- *
- * Input: unsigned channel channel number
- * unsigned position new playing position
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmSetPosition(unsigned channel, unsigned position)
- {
- dsmChannel *chan;
- int error;
-
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmSetPosition);
- return errInvalidChanNumber;
- }
-
- chan = &dsmChannels[channel];
-
- /* Convert position from bytes to samples: */
- position = position >> dsmSampleShift(chan->sampleType);
-
- /* Check if sample has been changed, and if so, set the values to the
- channel structure: */
- if ( chan->sampleChanged )
- {
- if ( (error = dsmChangeSample(channel)) != OK )
- PASSERROR(ID_dsmSetPosition)
-
- /* If channel status is released and the new channel does not have
- two loops, end the sample: */
- if ( (chan->loopMode != sdLoop1Rel) && (chan->loopMode != sdLoop2) &&
- (chan->status == dsmChanReleased) )
- {
- chan->status = dsmChanEnd;
- return OK;
- }
- }
-
- /* Check that sample and playing rate have been set on the channel: */
- if ( (chan->sampleHandle != 0) && (chan->rate != 0) )
- {
- switch ( chan->status )
- {
- case dsmChanEnd:
- case dsmChanPlaying:
- /* Either playing sample before releasing or playing has
- ended - check the first loop type: */
- chan->loopNum = 1;
- switch ( chan->loop1Type )
- {
- case loopNone:
- /* No looping - if position is below sample end, set
- it and start playing there: */
- if ( position < chan->sampleLength )
- {
- chan->playPos = position;
- chan->playPosLow = 0;
- chan->status = dsmChanPlaying;
- chan->direction = dsmPlayForward;
- }
- else
- chan->status = dsmChanEnd;
- break;
-
- case loopUnidir:
- /* Unidirectional looping - if position is below
- loop end, set it, otherwise set loop start as the
- new position. Start playing in any case: */
- if ( position < chan->loop1End )
- chan->playPos = position;
- else
- chan->playPos = chan->loop1Start;
- chan->playPosLow = 0;
- chan->status = dsmChanPlaying;
- chan->direction = dsmPlayForward;
- break;
-
- case loopBidir:
- /* Bidirectional looping - if position is below loop
- end, set it and start playing forward, otherwise
- set loop end as the new position and start playing
- backwards: */
- if ( position < chan->loop1End )
- {
- chan->playPos = position;
- chan->direction = dsmPlayForward;
- }
- else
- {
- chan->playPos = chan->loop1End;
- chan->direction = dsmPlayBackwards;
- }
- chan->playPosLow = 0;
- chan->status = dsmChanPlaying;
- }
- break;
-
- case dsmChanReleased:
- /* Playing after sample has been released - check second loop
- type: */
- chan->loopNum = 2;
- switch ( chan->loop2Type )
- {
- case loopNone:
- /* No looping - if position is below sample end, set
- it and start playing there: */
- if ( position < chan->sampleLength )
- {
- chan->playPos = position;
- chan->playPosLow = 0;
- chan->status = dsmChanPlaying;
- chan->direction = dsmPlayForward;
- }
- else
- chan->status = dsmChanEnd;
- break;
-
- case loopUnidir:
- /* Unidirectional looping - if position is below
- loop end, set it, otherwise set loop start as the
- new position. Start playing in any case: */
- if ( position < chan->loop2End )
- chan->playPos = position;
- else
- chan->playPos = chan->loop2Start;
- chan->playPosLow = 0;
- chan->status = dsmChanPlaying;
- chan->direction = dsmPlayForward;
- break;
-
- case loopBidir:
- /* Bidirectional looping - if position is below loop
- end, set it and start playing forward, otherwise
- set loop end as the new position and start playing
- backwards: */
- if ( position < chan->loop2End )
- {
- chan->playPos = position;
- chan->direction = dsmPlayForward;
- }
- else
- {
- chan->playPos = chan->loop2End;
- chan->direction = dsmPlayBackwards;
- }
- chan->playPosLow = 0;
- chan->status = dsmChanPlaying;
- }
- break;
-
- case dsmChanStopped:
- default:
- /* If sound has been stopped do nothing: */
- break;
- }
- }
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmGetPosition(unsigned channel, unsigned *position)
- *
- * Description: Reads the current playing position
- *
- * Input: unsigned channel channel number
- * unsigned *position pointer to playing position
- *
- * Returns: MIDAS error code. Playing position is written to *position.
- *
- \****************************************************************************/
-
- int CALLING dsmGetPosition(unsigned channel, unsigned *position)
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmGetPosition);
- return errInvalidChanNumber;
- }
-
- /* Write position to *position and convert to bytes: */
- *position = dsmChannels[channel].playPos << dsmSampleShift(
- dsmChannels[channel].sampleType);;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmGetDirection(unsigned channel, int *direction)
- *
- * Description: Reads current playing direction
- *
- * Input: unsigned channel channel number
- * int *direction pointer to playing direction. 1 is
- * forward, -1 backwards
- *
- * Returns: MIDAS error code. Playing direction is written to *direction.
- *
- \****************************************************************************/
-
- int CALLING dsmGetDirection(unsigned channel, int *direction)
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmGetDirection);
- return errInvalidChanNumber;
- }
-
- /* Write position to *position: */
- *direction = dsmChannels[channel].direction;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmSetPanning(unsigned channel, int panning)
- *
- * Description: Sets the panning position of a channel
- *
- * Input: unsigned channel channel number
- * int panning panning position (see enum sdPanning)
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmSetPanning(unsigned channel, int panning)
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmSetPanning);
- return errInvalidChanNumber;
- }
-
- /* Set panning position to channel: */
- dsmChannels[channel].panning = panning;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmGetPanning(unsigned channel, int *panning)
- *
- * Description: Reads the panning position of a channel
- *
- * Input: unsigned channel channel number
- * int *panning pointer to panning position
- *
- * Returns: MIDAS error code. Panning position is written to *panning.
- *
- \****************************************************************************/
-
- int CALLING dsmGetPanning(unsigned channel, int *panning)
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmGetPanning);
- return errInvalidChanNumber;
- }
-
- /* Write panning position to *panning: */
- *panning = dsmChannels[channel].panning;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmMuteChannel(unsigned channel, int mute)
- *
- * Description: Mutes/un-mutes a channel
- *
- * Input: unsigned channel channel number
- * int mute muting status - 1 = mute, 0 = un-mute
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmMuteChannel(unsigned channel, int mute)
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmMuteChannel);
- return errInvalidChanNumber;
- }
-
- /* Set muting status: */
- dsmChannels[channel].muted = mute;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmAddSample(sdSample *sample, int copySample,
- * unsigned *smpHandle);
- *
- * Description: Adds a new sample to the DSM sample list and prepares it for
- * DSM use
- *
- * Input: sdSample *sample pointer to sample information
- * structure
- * int copySample copy sample data to a new place in
- * memory? 1 = yes, 0 = no
- * unsigned *smpHandle pointer to sample handle
- *
- * Returns: MIDAS error code. Sample handle for the new sample is written
- * to *smpHandle
- *
- * Notes: If copySample = 1, sample data must not be in EMS memory.
- * If copySample = 0 and sample is 16-bit, the sample data WILL
- * be modified by this function.
- *
- \****************************************************************************/
-
- int CALLING dsmAddSample(sdSample *sample, int copySample, unsigned
- *smpHandle)
- {
- int i, handle, error;
- static void *copyDest;
- dsmSample *dsmSmp;
- unsigned destLength; /* destination sample length */
- int smpShift;
-
- /* Find first unused sample handle: */
- handle = 0;
- for ( i = 0; i < MAXSAMPLES; i++ )
- {
- if ( dsmSamples[i].inUse == 0 )
- {
- handle = i+1;
- break;
- }
- }
-
- /* Check if an empty handle was found. If not, return an error: */
- if ( handle == 0 )
- {
- ERROR(errNoSampleHandles, ID_dsmAddSample);
- return errNoSampleHandles;
- }
-
- /* Point dsmSmp to new sample: */
- dsmSmp = &dsmSamples[handle-1];
-
- /* Mark sample used: */
- dsmSmp->inUse = 1;
-
- smpShift = dsmSampleShift(sample->sampleType);
-
- /* Copy sample information: */
- dsmSmp->sampleType = sample->sampleType;
- dsmSmp->sampleLength = sample->sampleLength >> smpShift;
- dsmSmp->loopMode = sample->loopMode;
- dsmSmp->loop1Start = sample->loop1Start >> smpShift;
- dsmSmp->loop1End = sample->loop1End >> smpShift;
- dsmSmp->loop1Type = sample->loop1Type;
- dsmSmp->loop2Start = sample->loop2Start >> smpShift;
- dsmSmp->loop2End = sample->loop2End >> smpShift;
- dsmSmp->loop2Type = sample->loop2Type;
-
- if ( (sample->sampleType == smpNone) || (sample->sampleLength == 0) ||
- (sample->sample == NULL) || (sample->samplePos == sdSmpNone) )
- {
- /* There is no sample - set up DSM sample structure accordingly: */
- dsmSmp->sampleType = smpNone;
- dsmSmp->sampleLength = 0;
- dsmSmp->sample = NULL;
- dsmSmp->copied = 0;
- dsmSmp->samplePos = sdSmpNone;
- }
- else
- {
- if ( copySample )
- {
- /* Sample data should be copied elsewhere in memory */
- destLength = sample->sampleLength;
-
- /* Allocate memory for sample: */
- if ( (error = memAlloc(destLength, (void**) &dsmSmp->sample))
- != OK )
- PASSERROR(ID_dsmAddSample)
-
- copyDest = dsmSmp->sample;
-
- /* Sample is in conventional memory: */
- dsmSmp->samplePos = sdSmpConv;
-
- /* Copy sample data: */
- mMemCopy(copyDest, sample->sample, destLength);
-
- /* Sample is copied and should be deallocated when removed: */
- dsmSmp->copied = 1;
- }
- else
- {
- /* There is sample data, but it should not be copied - copy sample
- pointer and position: */
- dsmSmp->sample = sample->sample;
- dsmSmp->samplePos = sample->samplePos;
- dsmSmp->copied = 0;
- }
- }
-
- /* Write sample handle to *smpHandle: */
- *smpHandle = handle;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmRemoveSample(unsigned smpHandle)
- *
- * Description: Removes a sample from the sample list and deallocates it if
- * necessary.
- *
- * Input: unsigned smpHandle sample handle returned by
- * dsmAddSample()
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmRemoveSample(unsigned smpHandle)
- {
- dsmSample *sample;
- int error;
-
- /* Check that the sample handle is valid and the sample is in use: */
- if ( (smpHandle > MAXSAMPLES) || (dsmSamples[smpHandle-1].inUse == 0) )
- {
- ERROR(errInvalidSampleHandle, ID_dsmRemoveSample);
- return errInvalidSampleHandle;
- }
-
- sample = &dsmSamples[smpHandle-1];
-
- /* Mark sample unused: */
- sample->inUse = 0;
-
- /* Check if sample data should be deallocated: */
- if ( sample->copied )
- {
- if ( (error = memFree(sample->sample)) != OK )
- PASSERROR(ID_dsmRemoveSample)
- }
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmMixData(unsigned numElems)
- *
- * Description: Mixes data to dsmMixBuffer.
- *
- * Input: unsigned numElems number of buffer elements to be mixed.
- * In mono modes an "element" is an
- * unsigned integer, and in stereo
- * two.
- *
- * Returns: MIDAS error code. Mixed data is written to *dsmMixBuffer.
- *
- \****************************************************************************/
-
- int CALLING dsmMixData(unsigned numElems)
- {
- int error;
- unsigned ch;
- unsigned volume;
- dsmChannel *chan;
- void *mixRoutine;
-
- /* If playing is paused, no channels are open or data on channels may not
- be used, just clear the buffer and exit: */
- if ( dsmPaused || (dsmChOpen == 0) || (!dsmChPlay) )
- {
- if ( (error = dsmClearBuffer(numElems)) != OK )
- PASSERROR(ID_dsmMixData)
- return OK;
- }
-
- for ( ch = 0; ch < dsmChOpen; ch++ )
- {
- chan = &dsmChannels[ch];
-
- /* Point mixRoutine to correct low-level mixing routine: */
- mixRoutine = mixingRoutines[dsmMode][chan->sampleType];
-
- /* If current channel is muted or DSM is muted, set channel volume to
- zero, otherwise calculate it: */
- if ( chan->muted || dsmMuted )
- volume = 0;
- else
- volume = (chan->volume * dsmMasterVolume) / 64;
-
- /* Mix data for this channel: */
- if ( (error = dsmMix(ch, mixRoutine, volume, numElems)) != OK )
- PASSERROR(ID_dsmMixData)
- }
-
- return OK;
- }
-
-
-
- #ifdef SUPPORTSTREAMS
-
-
- /****************************************************************************\
- *
- * Function: int dsmStartStream(unsigned channel, uchar *buffer,
- * unsigned bufferLength, int sampleType);
- *
- * Description: Starts playing a digital audio stream on a channel
- *
- * Input: unsigned channel channel number
- * uchar *buffer pointer to stream buffer
- * unsigned bufferLength buffer length in bytes
- * int sampleType stream sample type
- * ulong rate stream playing rate (in Hz)
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmStartStream(unsigned channel, uchar *buffer, unsigned
- bufferLength, int sampleType, ulong rate)
- {
- dsmChannel *chan;
-
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmStartStream);
- return errInvalidChanNumber;
- }
-
- chan = &dsmChannels[channel];
-
- /* Set up channel for playing the stream: */
- chan->sample = buffer;
- chan->sampleType = sampleType;
- chan->samplePos = sdSmpConv;
- chan->sampleLength = bufferLength >> dsmSampleShift(sampleType);
- chan->loopMode = sdLoop1;
- chan->loop1Start = 0;
- chan->loop1End = bufferLength >> dsmSampleShift(sampleType);
- chan->loop1Type = loopUnidir;
- chan->loop2Start = chan->loop2End = 0;
- chan->loop2Type = sdLoopNone;
- chan->playPos = chan->playPosLow = 0;
- chan->rate = rate;
- chan->direction = dsmPlayForward;
- chan->sampleHandle = DSM_SMP_STREAM; /* magic */
- chan->sampleChanged = 0;
- chan->panning = panMiddle;
- chan->volume = 64;
- chan->muted = 0;
- chan->loopNum = 1;
- chan->status = dsmChanPlaying;
- chan->streamWritePos = 0;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmStopStream(unsigned channel);
- *
- * Description: Stops playing digital audio stream on a channel
- *
- * Input: unsigned channel channel number
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmStopStream(unsigned channel)
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmStopSound);
- return errInvalidChanNumber;
- }
-
- /* Stop sound: */
- dsmChannels[channel].status = dsmChanStopped;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmSetLoopCallback(unsigned channel,
- * void (CALLING *callback)(unsigned channel));
- *
- * Description: Sets sample looping callback to a channel
- *
- * Input: unsigned channel channel number
- * [..] *callback pointer to callback function, NULL to
- * disable callback
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmSetLoopCallback(unsigned channel,
- void (CALLING *callback)(unsigned channel))
- {
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmStopSound);
- return errInvalidChanNumber;
- }
-
- /* Set callback: */
- dsmChannels[channel].LoopCallback = callback;
-
- return OK;
- }
-
-
-
-
- /****************************************************************************\
- *
- * Function: int dsmSetStreamWritePosition(unsigned channel,
- * unsigned position)
- *
- * Description: Sets the stream write position on a channel
- *
- * Input: unsigned channel channel number
- * unsigned position new stream write position
- *
- * Returns: MIDAS error code
- *
- \****************************************************************************/
-
- int CALLING dsmSetStreamWritePosition(unsigned channel, unsigned position)
- {
- dsmChannel *chan;
-
- /* Check that the channel number is legal and channels are open: */
- if ( channel >= dsmChOpen )
- {
- ERROR(errInvalidChanNumber, ID_dsmSetStreamWritePosition);
- return errInvalidChanNumber;
- }
-
- chan = &dsmChannels[channel];
-
- chan->streamWritePos = position >> dsmSampleShift(chan->sampleType);
-
- return OK;
- }
-
-
-
-
- #endif /* #ifdef SUPPORTSTREAMS */
-
-
-
-
- /*
- * $Log: dsm.c,v $
- * Revision 1.11 1997/01/16 18:41:59 pekangas
- * Changed copyright messages to Housemarque
- *
- * Revision 1.10 1997/01/16 18:19:10 pekangas
- * Added support for setting the stream write position.
- * Stream data is no longer played past the write position
- *
- * Revision 1.9 1996/10/09 15:54:22 pekangas
- * Fixed dsmReleaseSound() to work as specified
- *
- * Revision 1.8 1996/07/13 19:44:22 pekangas
- * Eliminated Visual C warnings
- *
- * Revision 1.7 1996/07/13 18:40:48 pekangas
- * Fixed to compile with Visual C
- *
- * Revision 1.6 1996/06/26 19:14:55 pekangas
- * Added sample loop callbacks
- *
- * Revision 1.5 1996/05/30 21:10:27 pekangas
- * Fixed a small bug in looping other samples than 8-bit mono
- *
- * Revision 1.4 1996/05/28 20:31:11 pekangas
- * Added support for 8-bit stereo and 16-bit mono and stereo samples
- *
- * Revision 1.3 1996/05/26 20:55:39 pekangas
- * Implemented digital audio stream support
- *
- * Revision 1.2 1996/05/24 16:19:39 jpaana
- * Misc fixes for Linux
- *
- * Revision 1.1 1996/05/22 20:49:33 pekangas
- * Initial revision
- *
- */